
#include <stdio.h>
#include <cegfx/ceboundingbox.h>

ceBoundingBox::ceBoundingBox ()
{
	Clear ();
}


void ceBoundingBox::Clear ()
{
	min = D3DXVECTOR3 (0, 0, 0);
	max = D3DXVECTOR3 (0, 0, 0);
	center = D3DXVECTOR3 (0, 0, 0);
	inited = false;
}


void ceBoundingBox::AddVector3 (const D3DXVECTOR3& v)
{
	if (inited)
	{
		if (min.x > v.x) min.x = v.x;
		if (min.y > v.y) min.y = v.y;
		if (min.z > v.z) min.z = v.z;
		if (max.x < v.x) max.x = v.x;
		if (max.y < v.y) max.y = v.y;
		if (max.z < v.z) max.z = v.z;
	}
	else
	{
		min = max = v;
		inited = true;
	}
}

void ceBoundingBox::AddVector3 (float x, float y, float z)
{
	if (inited)
	{
		if (min.x > x) min.x = x;
		if (min.y > y) min.y = y;
		if (min.z > z) min.z = z;
		if (max.x < x) max.x = x;
		if (max.y < y) max.y = y;
		if (max.z < z) max.z = z;
	}
	else
	{
		min = max = D3DXVECTOR3(x, y, z);
		inited = true;
	}
}


void ceBoundingBox::AddBoundingBox(const ceBoundingBox& bbox)
{
	AddVector3 (bbox.p[0]);
	AddVector3 (bbox.p[1]);
	AddVector3 (bbox.p[2]);
	AddVector3 (bbox.p[3]);
	AddVector3 (bbox.p[4]);
	AddVector3 (bbox.p[5]);
	AddVector3 (bbox.p[6]);
	AddVector3 (bbox.p[7]);
}

void ceBoundingBox::AddBorder (float x, float y, float z)
{
	min.x -= x;
	min.y -= y;
	min.z -= z;

	max.x += x;
	max.y += y;
	max.z += z;
}

void ceBoundingBox::Update ()
{
	center = (min + max) / 2.0f;

	p[0] = D3DXVECTOR3(min.x, min.y, min.z);
	p[1] = D3DXVECTOR3(min.x, min.y, max.z);
	p[2] = D3DXVECTOR3(min.x, max.y, min.z);
	p[3] = D3DXVECTOR3(min.x, max.y, max.z);
	p[4] = D3DXVECTOR3(max.x, min.y, min.z);
	p[5] = D3DXVECTOR3(max.x, min.y, max.z);
	p[6] = D3DXVECTOR3(max.x, max.y, min.z);
	p[7] = D3DXVECTOR3(max.x, max.y, max.z);
}

void ceBoundingBox::Transform (const D3DXMATRIX *matrix)
{
	static D3DXVECTOR4 t;
	Clear ();

	D3DXVec3Transform (&t, &p[0], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[1], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[2], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[3], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[4], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[5], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[6], matrix); AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[7], matrix); AddVector3 (t.x, t.y, t.z);

	Update();
}

void ceBoundingBox::Transform (const D3DXMATRIX* matrix, ceBoundingBox* bbox) const
{
	static D3DXVECTOR4 t;
	bbox->Clear ();

	D3DXVec3Transform (&t, &p[0], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[1], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[2], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[3], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[4], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[5], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[6], matrix); bbox->AddVector3 (t.x, t.y, t.z);
	D3DXVec3Transform (&t, &p[7], matrix); bbox->AddVector3 (t.x, t.y, t.z);

	bbox->Update();
}


const D3DXVECTOR3& ceBoundingBox::GetMin () const
{
	return min;
}

const D3DXVECTOR3& ceBoundingBox::GetMax () const
{
	return max;
}

const D3DXVECTOR3& ceBoundingBox::GetCenter () const
{
	return center;
}

const D3DXVECTOR3* ceBoundingBox::GetPoints () const
{
	return p;
}

void ceBoundingBox::Debug (const char* name) const
{
	printf ("BoundingBox[%s]: <%.2f %.2f %.2f> - <%.2f %.2f %.2f>\n",
		name,
		min.x, min.y, min.z,
		max.x, max.y, max.z);
}
